#include "jsonrpcserver.h"


#include <QMetaClassInfo>
#include <QStringList>

#include "jsonrpcservice.h"
#include "jsonrpcsocket.h"


void JsonRpcServer::addService(JsonRpcService* service){
    const QMetaObject *meta = service->metaObject();
    for (int i = 0; i < meta->classInfoCount(); i++) {
        const QMetaClassInfo info = meta->classInfo(i);
        if (QString(info.name()) == "serviceName"){
            v_serviceMap[info.value()] = service;
            QObject::connect(service, SIGNAL(notifyAll(QString,QVariantList)), this, SLOT(notify(QString,QVariantList)));
            return;
        }
    }


}



void JsonRpcServer::insertClient(QIODevice *device, JsonRpcSocket *socket){
    // Adds the new client to the list
    v_clientSocketMap[device] = socket;
    QObject::connect(socket, SIGNAL(jsonRpcRequestReceived(JsonRpcMessage)), this, SLOT(processJsonRpcMessage(JsonRpcMessage)));

}


void JsonRpcServer::removeClient(QIODevice *device){
    QMap<QIODevice*, JsonRpcSocket*>::iterator it = v_clientSocketMap.find(device);
    QObject::disconnect(it.value(), SIGNAL(jsonRpcRequestReceived(JsonRpcMessage)), this, SLOT(processJsonRpcMessage(JsonRpcMessage)));
    delete it.value();
    v_clientSocketMap.erase(it);

}


void JsonRpcServer::notify(const QString& methodName, const QVariantList& params){
    JsonRpcMessage notif = JsonRpcMessage::createNotification(methodName, params);
    QList<JsonRpcSocket*> sockets = v_clientSocketMap.values();
    for(int i=0; i<sockets.count(); i++){
        sockets.at(i)->sendMessage(notif);
    }
}


// SLOT
void JsonRpcServer::processJsonRpcMessage(const JsonRpcMessage& request)
{
    JsonRpcSocket *client = static_cast<JsonRpcSocket*>(QObject::sender());
    QVariant returnValue;

    switch(request.type()){
    case JsonRpcMessage::Request:
    {
        QString method = request.method();
        QStringList splitted = method.split(".");
        JsonRpcService *service = v_serviceMap[splitted.at(0)];
        if(service == NULL){
            JsonRpcMessage error = request.createError(JsonRpcMessage::ServiceNotFound, "Service not found");
            client->sendMessage(error);
            return;
        }

        int errorCode = JsonRpcService::invokeSlot(service, splitted.at(1), request.params(), returnValue);

        JsonRpcMessage resultMessage;
        switch(errorCode){
            case JsonRpcMessage::MethodNotFound:
                resultMessage = request.createError(JsonRpcMessage::MethodNotFound, "Method not found");
            case JsonRpcMessage::DifferentSignature:
                resultMessage = request.createError(JsonRpcMessage::DifferentSignature, "Different signature");
            case JsonRpcMessage::NoError:
                resultMessage = request.createResponse(returnValue);

        }


        client->sendMessage(resultMessage);
        break;
    }
    default:
        break;
    }
}
